using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using Pegasus.Runtime.Serialization;
using RollManager.Library;
using RollManager.Library.ActionSteps;
using Pegasus.Log4Net;

namespace RollManager.Forms.DetailsPanels
{
    public partial class SubActionDetailsPanel : UserControl, DetailsPanel
    {
        private static ILog s_logger = LogManager.GetLogger( typeof( SubActionDetailsPanel ) );

        private static List<ActionStep> s_stepTypes;
        private readonly SubAction m_subAction;
        private int m_curIndex;

        private ServerGroup Server
        {
            get
            {
                return (ServerGroup) serverGroupList.SelectedItem;
            }
        }

        static SubActionDetailsPanel()
        {
            s_stepTypes = new List<ActionStep>();

            // Look at all libraries in working folder.
            foreach( string dllFilename in Directory.GetFiles( Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location ), "*.dll" ) )
            {
                Assembly assembly = null;
                try
                {
                    assembly = Assembly.LoadFile( dllFilename );
                }
                catch( BadImageFormatException ex )
                {
                    s_logger.WarnFormat( ex, "Couldn't load assembly {0}", dllFilename );
                    continue;
                }

                // Iterate over action steps, construct step and add to list.
                foreach( Type t in assembly.GetTypes() )
                {
                    if( t.IsSubclassOf( typeof( ActionStep ) ) && !t.IsAbstract )
                    {
                        ConstructorInfo constructor = t.GetConstructor( Type.EmptyTypes );

                        ActionStep step = (ActionStep) constructor.Invoke( null );

                        if( !string.IsNullOrEmpty( step.Name ) )
                        {
                            s_stepTypes.Add( step );
                        }
                    }
                }
            }

            s_stepTypes.Sort( delegate( ActionStep x, ActionStep y ) { return x.Name.CompareTo( y.Name ); } );
        }

        public SubActionDetailsPanel( SubAction subAction )
        {
            InitializeComponent();

            m_subAction = subAction;

            // populate server group list.
            serverGroupList.DataSource = Database.GetServerGroups();
            serverGroupList.DisplayMember = ItemBase.NAME_PROPERTY;

            // select server group currently used by sub action.
            for(int i=0;i<serverGroupList.Items.Count; i++)
            {
                if( ( (ServerGroup) serverGroupList.Items[ i ] ).Id == m_subAction.ServerGroupId )
                {
                    serverGroupList.SelectedIndex = i;
                    break;
                }
            }

            // populate available steps list
            availableStepsList.DisplayMember = "Name";
            foreach( ActionStep step in s_stepTypes )
            {
                availableStepsList.Items.Add( step );
            }

            // populate steps list
            stepsList.DisplayMember = "Name";
            foreach( ActionStep step in m_subAction.StepList )
            {
                stepsList.Items.Add( step );
            }
            if( stepsList.Items.Count > 0 )
            {
                stepsList.SelectedIndex = 0;
                stepsList_Click( null, null );
            }

            nameBox.Text = m_subAction.Name;
            ownerLabel.Text = m_subAction.OwnerName;
            permissionsList.DataSource = Enum.GetValues( typeof( Permission ) );
            permissionsList.SelectedItem = m_subAction.Permission;

            // decide how to offer permissions adjusting
            if( m_subAction.UserOwned )
            {
                permissionsLabel.Visible = false;
            }
            else
            {
                if( m_subAction.Permission == Permission.Public )
                {
                    permissionsLabel.Text = "Public - changes are saved.";
                }
                else
                {
                    permissionsLabel.Text = "Read Only - changes are discarded.";
                }
                permissionsList.Visible = false;
            }
        }

        public void Save()
        {
            if( m_subAction.Saveable )
            {
                // Retrieve and serialize list of steps
                List<ActionStep> steps = new List<ActionStep>();
                foreach( ActionStep step in stepsList.Items )
                {
                    steps.Add( step );
                }
                m_subAction.StepList = steps;

                m_subAction.Name = nameBox.Text;
                m_subAction.ServerGroupId = Server.Id;
                m_subAction.Permission = (Permission) permissionsList.SelectedValue;

                Database.SaveSubAction( m_subAction );
            }
        }

        private void availableStepsList_DoubleClick( object sender, System.EventArgs e )
        {
            // Get type of selected step.
            ActionStep stepType = availableStepsList.SelectedItem as ActionStep;
            if( stepType == null )
            {
                return;
            }

            // Construct step.
            ConstructorInfo constructor = stepType.GetType().GetConstructor( Type.EmptyTypes );
            ActionStep step = (ActionStep) constructor.Invoke( null );

            // Show setup dialog for step and add to list if accepted by user.
            if( new SetupStepDialog( step ).ShowDialog() == DialogResult.OK )
            {
                stepsList.Items.Add( step );
            }
        }

        private void stepsList_MouseDown( object sender, MouseEventArgs e )
        {
            if( e.Button == MouseButtons.Left )
            {
                int index = stepsList.IndexFromPoint( e.X, e.Y );
                if( index != -1)
                {
                    m_curIndex = index;
                }
            }
        }

        private void stepsList_MouseMove( object sender, MouseEventArgs e )
        {
            if( e.Button == MouseButtons.Left )
            {
                int index = stepsList.IndexFromPoint( e.X, e.Y );
                if( index != -1 && index != m_curIndex )
                {
                    object temp = stepsList.Items[ index ];
                    stepsList.Items[ index ] = stepsList.Items[ m_curIndex ];
                    stepsList.Items[ m_curIndex ] = temp;
                    m_curIndex = index;
                }
            }
        }

        private void stepsList_Click( object sender, System.EventArgs e )
        {
            propertyGrid.SelectedObject = stepsList.SelectedItem;
            if( stepsList.SelectedItem != null )
            {
                stepLbl.Text = ( (ActionStep) stepsList.SelectedItem ).Name;
            }
        }

        private void configSettingBtn_Click( object sender, System.EventArgs e )
        {
            ConfigSettings dialog = new ConfigSettings();
            dialog.Show( this );
        }

        private void stepsList_DoubleClick( object sender, System.EventArgs e )
        {
            if( stepsList.SelectedIndex < 0 )
            {
                return;
            }

            if( Common.ConfirmAction( "Do you want to delete this step?", "Confirm step removal" ) )
            {
                stepsList.Items.RemoveAt( stepsList.SelectedIndex );
            }
        }

        private void availableStepsList_KeyPress( object sender, KeyPressEventArgs e )
        {
            if( e.KeyChar == (int) Keys.Enter )
            {
                availableStepsList_DoubleClick( sender, e );
            }
        }

        private void stepsList_KeyDown( object sender, KeyEventArgs e )
        {
            if( e.KeyCode == Keys.Delete )
            {
                stepsList_DoubleClick( sender, e );
                return;
            }

            if( !e.Control || stepsList.SelectedIndex < 0 )
            {
                return;
            }

            if( e.KeyCode == Keys.X )
            {
                Clipboard.SetText( SerializationHelper.ObjectToXml( stepsList.SelectedItem ) );
                stepsList.Items.RemoveAt( stepsList.SelectedIndex );
            }
            else if( e.KeyCode == Keys.C )
            {
                Clipboard.SetText( SerializationHelper.ObjectToXml( stepsList.SelectedItem ) );
            }
            else if( e.KeyCode == Keys.V && Clipboard.ContainsText() )
            {
                try
                {
                    ActionStep step = (ActionStep) SerializationHelper.XmlToObject( Clipboard.GetText() );
                    stepsList.Items.Add( step );
                }
                catch {}
            }
        }
    }
}